package com.juhuixing.gateway.service;

import com.alibaba.fastjson.JSONObject;
import com.google.common.io.CharStreams;
import com.juhuixing.gateway.util.SnowflakeIdWorker;
import com.netflix.zuul.context.RequestContext;
import com.juhuixing.gateway.model.LogInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.cloud.netflix.ribbon.apache.RibbonApacheHttpResponse;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 刘天元
 * @description 记录日志
 * @create 2018-06-25 13:39
 **/
@Service
@Slf4j
public class LogService {

    private final String LOG_INFO = "logInfo";

    public void handlePreLog(RequestContext requestContext) {
        LogInfoDTO logInfo = new LogInfoDTO();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        logInfo.setCreateTime(format.format(new Date()));
        logInfo.setStartTime(System.currentTimeMillis());
        HttpServletRequest request = requestContext.getRequest();
        String requestUrl = request.getRequestURL().toString();
        String method = request.getMethod();
        String params = JSONObject.toJSONString(request.getParameterMap());
        String version = requestContext.getZuulRequestHeaders().get("version");
        String source = requestContext.getZuulRequestHeaders().get("source");
        String imei = requestContext.getZuulRequestHeaders().get("imei");
        String deviceInfo = requestContext.getZuulRequestHeaders().get("deviceInfo");
        Long requestId = SnowflakeIdWorker.generateId();
        requestContext.addZuulRequestHeader("requestid", requestId.toString());
        logInfo.setRequestId(requestId);
        logInfo.setAccessToken(requestContext.getZuulRequestHeaders().get("Authorization"));
        logInfo.setUserAgent(request.getHeader("user-agent"));
        logInfo.setRequestUrl(requestUrl);
        logInfo.setMethod(method);
        logInfo.setParams(params);
        logInfo.setVersion(version);
        logInfo.setSource(source);
        logInfo.setImei(imei);
        logInfo.setDeviceInfo(deviceInfo);
        requestContext.put(LOG_INFO, logInfo);
    }

    public void handlePostLog(RequestContext requestContext) {
        LogInfoDTO logInfo = (LogInfoDTO) requestContext.get(LOG_INFO);
        logInfo.setEndTime(System.currentTimeMillis());
        logInfo.setTime(logInfo.getEndTime() - logInfo.getStartTime());
        logInfo.setResponseStatusCode(requestContext.getResponseStatusCode());

        RibbonApacheHttpResponse ribbonResponse = (RibbonApacheHttpResponse) requestContext.get("ribbonResponse");
        if(ribbonResponse!=null) {
            String redirectHost = ribbonResponse.getRequestedURI().getHost();
            int redirectPort = ribbonResponse.getRequestedURI().getPort();
            logInfo.setRedirectHost(redirectHost);
            logInfo.setRedirectPort(redirectPort);
        }

        if (StringUtils .isNotEmpty(requestContext.getResponseBody())) {
            logInfo.setResponseData(requestContext.getResponseBody());
        }

        Throwable throwable = requestContext.getThrowable();
        if (throwable != null) {
            Throwable cause = throwable.getCause();
            while (cause.getCause()!=null) {
                cause = cause.getCause();
            }

            StringWriter sw = new StringWriter();
            cause.printStackTrace(new PrintWriter(sw, true));
            logInfo.setException(sw.getBuffer().toString());
            // 打印zuul抛出的异常
            log.error("zuul异常捕获", throwable);
        }
        if (logInfo.getResponseStatusCode() == HttpStatus.SC_OK) {
            /// 避免日志输出太多
            //log.info(logInfo.toString());
        } else {
            if(throwable == null) {
                //打印微服务抛出的异常
                log.error(logInfo.toString());
            }
            if(StringUtils.isEmpty(logInfo.getResponseData()) && requestContext.getResponseDataStream()!=null) {
                try (final InputStream responseDataStream = requestContext.getResponseDataStream()) {
                    final String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
                    requestContext.setResponseBody(responseData);
                    logInfo.setResponseData(responseData);
                } catch (IOException e) {
                    log.error("Error reading body",e);
                }
            }
        }
    }
}
